package models.application;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.*;

import com.avaje.ebean.ExpressionList;
import com.mysql.jdbc.StringUtils;
import models.pubobj.AniObjectState;
import models.user.AniUser;

import play.data.validation.Constraints;
import play.db.ebean.Model;
import utils.AniGeneralUtils;
import utils.MVCUtils;

@Entity
public class AniUserAppRel extends Model {

    @Id
	public Long id;
	
	@ManyToOne
	public AniUser clientUser;
	
	@ManyToOne
	public AniApp targetApp;
	
	@ManyToOne
	public AniObjectState state;

    public AniUserAppRel(AniUser clientUser, AniApp targetApp, AniObjectState state) {
        this.clientUser = clientUser;
        this.targetApp = targetApp;
        this.state = state;
    }

    public AniUserAppRel(Long id, AniUser clientUser, AniApp targetApp, AniObjectState state) {
        this.id = id;
        this.clientUser = clientUser;
        this.targetApp = targetApp;
        this.state = state;
    }

    public static Model.Finder<Long, AniUserAppRel> find = new Model.Finder(Long.class, AniUserAppRel.class);
	
	public static AniUserAppRel withClientAppIdTargetApiId(Long clientAppId, Long targetApiId){
		return find.where().eq("clientApp.id", clientAppId).eq("targetApi.id", targetApiId).findUnique();
	}
	
	public static List<AniUserAppRel> findAll() {
        return find.all();
    }

    public static List<AniUserAppRel> searchUserInstalledApp(
            AniUser installedUser,
            Map<String, Object> queryElements,
            String queryKeyword,
            Integer page
    ){
        AniObjectState activatedState = AniObjectState.findByStateKey(
                AniObjectState.States.ACTIVATED.name()
        );
        queryElements.put(
                "state.id",
                activatedState.id
        );
        queryElements.put(
                "clientUser.id", installedUser.id
        );
        queryElements.put(
                "targetApp.state.id",
                activatedState.id
        );
        queryKeyword = StringUtils.isEmptyOrWhitespaceOnly(queryKeyword) ? "" : queryKeyword;
        ExpressionList basicExpression = find
                .fetch("targetApp")
                .fetch("clientUser")
                .fetch("targetApp.appClassification")
                .where()
                .allEq(queryElements)
                .or(
                        find.getExpressionFactory().like("targetApp.appName", "%" + queryKeyword + "%"),
                        find.getExpressionFactory().like("targetApp.description", "%" + queryKeyword + "%")
                );
        if(page >= 0){
            return basicExpression
                    .findPagingList(Integer.parseInt(MVCUtils.getConfig("wd.page.size")))
                    .getPage(page)
                    .getList();
        }else{
            return basicExpression.findList();
        }
    }

    public static Integer searchUserInstalledAppTotalCount(
            AniUser installedUser,
            Map<String, Object> queryElements,
            String queryKeyword
    ){
        AniObjectState activatedState = AniObjectState.findByStateKey(
                AniObjectState.States.ACTIVATED.name()
        );
        queryElements.put(
                "state.id",
                activatedState.id
        );
        queryElements.put(
                "clientUser.id", installedUser.id
        );
        queryElements.put(
                "targetApp.state.id",
                activatedState.id
        );
        queryKeyword = StringUtils.isEmptyOrWhitespaceOnly(queryKeyword) ? "" : queryKeyword;
        ExpressionList basicExpression = find
                .where()
                .allEq(queryElements)
                .or(
                        find.getExpressionFactory().like("targetApp.appName", "%" + queryKeyword + "%"),
                        find.getExpressionFactory().like("targetApp.description", "%" + queryKeyword + "%")
                );
        return basicExpression.findRowCount();
    }

    public static Integer getInstalledAppCount(List<AniApp> apps, AniUser clientUser){
        return find.where()
                .eq("clientUser", clientUser)
                .in("targetApp", apps)
                .findRowCount();
    }

    public static List<AniUserAppRel> getInstalledAppsList(List<AniApp> apps, AniUser clientUser){
        return find.where()
                .eq("clientUser", clientUser)
                .in("targetApp", apps)
                .eq("state.id", AniObjectState.findByStateKey(AniObjectState.States.ACTIVATED.name()).id)
                .findList();
    }
    public static Map<Long, AniApp> getInstalledAppsMap(List<AniApp> apps, AniUser clientUser){
        List<AniUserAppRel> installedAppRels = getInstalledAppsList(apps, clientUser);
        //app map
        return generateAppIdMap(installedAppRels);
    }
    public static Map<Long, AniUserAppRel> getInstalledAppsUserRelMap(List<AniApp> apps, AniUser clientUser){
        List<AniUserAppRel> installedAppRels = getInstalledAppsList(apps, clientUser);
        //app map
        return generateAppIdUserRelMap(installedAppRels);
    }
    private static Map<Long, AniUserAppRel> generateAppIdUserRelMap(List<AniUserAppRel> appRels){
        Map<Long, AniUserAppRel> installedAppsRel = new LinkedHashMap<Long, AniUserAppRel>();
        for(AniUserAppRel oneAppRel: appRels){
            installedAppsRel.put(oneAppRel.targetApp.id, oneAppRel);
        }
        return installedAppsRel;
    }
    private static Map<Long, AniApp> generateAppIdMap(List<AniUserAppRel> appRels){
        Map<Long, AniApp> installedApps = new LinkedHashMap<Long, AniApp>();
        for(AniUserAppRel oneAppRel: appRels){
            installedApps.put(oneAppRel.targetApp.id, oneAppRel.targetApp);
        }
        return installedApps;
    }
}
